#include "stdafx.h"
#include "GameStateUserInterface.h"

#include "Event.h"
#include "EntityEvent.h"

#include "Timer.h"
#include "Menus\Label.h"
#include "Time\TimeManager.h"
#include "World\World.h"

#include "InputManager.h"

#include "BoundingBoxComponent.h"
#include "Components\CameraComponent.h"
#include "Components\GaulemRenderableComponent.h"
#include "Utilities\CameraHelper.h"
#include "States\GameStateObject.h"

#include "Menus\Picture.h"

using namespace ZeEngine;
using namespace std;

GameStateUserInterface::GameStateUserInterface(GUISystem& guiSystem, std::shared_ptr<GameStateObject> pGameStateObject) : UserInterface(guiSystem),
                                                                                                                          m_pGameStateObject(pGameStateObject),
                                                                                                                          m_pBaseCameraComponent(nullptr),
                                                                                                                          m_pGaulemCameraComponent(nullptr),
																										                  m_pFastForward(NULL),
                                                                                                                          m_pFastBackward(NULL), 
                                                                                                                          m_pFPS(NULL), 
                                                                                                                          m_pTime(NULL),
                                                                                                                          m_pGameEngine(nullptr),
                                                                                                                          m_state(eShowingNothingOnMouse)
{
}

GameStateUserInterface::~GameStateUserInterface()
{
}

bool GameStateUserInterface::Init(GameEngine& gameEngine)
{
    GUISystem& gui = gameEngine.GetGUISystem();
    m_pGameEngine = &gameEngine;

    m_clickTimer = make_unique<Timer>();

    m_resolution = gameEngine.GetConfiguration().GetLogicalResolution();

    Vector2D<u32> position = Vector2D<u32>((m_resolution.GetX() / 2), (m_resolution.GetY() / 4));
    m_pFastForward = make_shared<Button>("btn_forward_up", "btn_forward_down", "btn_forward_hover", position);
    m_pFastForward->SetListener(this);
    AddControl(m_pFastForward);

    position = Vector2D<u32>(static_cast<u32>((m_resolution.GetX() / 2) - (m_pFastForward->GetSize().GetX())), (m_resolution.GetY() / 4));
    m_pFastBackward = make_shared<Button>("btn_backward_up", "btn_backward_down", "btn_backward_hover", position);
    m_pFastBackward->SetListener(this);
    AddControl(m_pFastBackward);

    //Label
    SDL_Color color = {0, 0, 255, 255};
    m_pFPS = make_shared<Label>("temp_font", "FPS:", Vector2D<float>(), 24, color);
    AddControl(m_pFPS);

    position = m_pFastForward->GetRelativePosition() + Vector2D<float>(m_pFastForward->GetSize().GetX(), 0);
    m_pTime = make_shared<Label>("temp_font", "", position, 24, color);
    AddControl(m_pTime);
 
    AddControl(make_shared<Picture>("menubar_bottom", Vector2D<s32>(0, m_resolution.GetY() - 64)));

    m_128Button = make_shared<Button>("btn128", "btn128", "btn128", Vector2D<s32>(0, m_resolution.GetY() - 64));
    m_128Button->SetListener(this);
    AddControl(m_128Button);

    m_pBtnReport = make_shared<Button>("btn_report_up", "btn_report_down", "btn_report_hover", Vector2D<s32>(m_resolution.GetX() - 40, m_resolution.GetY() / 3));
    m_pBtnReport->SetListener(this);
    AddControl(m_pBtnReport);

    m_reportPicture = make_shared<Picture>("game_interface", "board", Vector2D<s32>(m_resolution.GetX() -600 , 0));
  
    m_reportPicture->AddChild(make_shared<Label>("temp_font", "Press 1 to spawn bonhommes", Vector2D<float>(105, 100), 18, color));
    m_reportPicture->AddChild(make_shared<Label>("temp_font", "Press 2 to quit", Vector2D<float>(105, 125), 18, color));
    m_reportPicture->Hide();
    AddControl(m_reportPicture);

    gameEngine.AddEventListener(this);
    InputManager::AddMouseListener(this, "GameStateUserInterface");

    m_activePictureOnMouse = make_shared<Picture>("temp_tiles", "128", Vector2D<s32>(0, 0));
    AddControl(m_activePictureOnMouse);
    m_activePictureOnMouse->Hide();

    return true;
}

bool GameStateUserInterface::Update(ZeEngine::GameEngine& gameEngine)
{
    if (m_pFPS)
    {
        u32 fps = gameEngine.GetFPS();
        stringstream ss;
        ss << "FPS: " << fps;
        m_pFPS->SetText(ss.str());
    }

    if (m_elapsedClickTime > 0 && m_elapsedClickTime <100)
    {
        m_pGameStateObject->ClearEntitiesOfInterest();

        for (auto& entity : m_clickedEntities)
        {
            m_pGameStateObject->AddEntityOfInterest(entity);
        }
        m_clickedEntities.clear();

        m_elapsedClickTime = 0;
    }

    if (m_pTime)
    {
        m_pTime->SetText(m_pGameStateObject->GetTimeManager().ToString());
    }

    return false;
}

void GameStateUserInterface::Destroy(GameEngine& gameEngine)
{
    gameEngine.RemoveEventListener(this);
    InputManager::RemoveMouseListener("GameStateUserInterface");
    UserInterface::Destroy(gameEngine);
}

void GameStateUserInterface::OnButtonClicked(u32 id)
{
    if (id == m_pFastForward->GetID())
    {
        m_pGameStateObject->GetTimeManager().IncreaseSpeed();
    }
    else if (id == m_pFastBackward->GetID())
    {
        m_pGameStateObject->GetTimeManager().DecreaseSpeed();
    }
    else if (id == m_128Button->GetID())
    {
        SetActivePictureOnMouse("temp_tiles", "128");
    }
    else if (id == m_pBtnReport->GetID())
    {
        m_reportPicture->IsHidden() ? m_reportPicture->Show() : m_reportPicture->Hide();
    }
}

void GameStateUserInterface::FindClickedEntities(GameEngine& gameEngine, Vector2D<s32> mousePosition)
{
    EntityManager& entityManager = gameEngine.GetEntityManager();

    auto yOffset = static_cast<s32>(gameEngine.GetConfiguration().GetLogicalResolution().GetY() / 4);

    m_clickedEntities.clear();

    bool fTop = mousePosition.GetY() < yOffset;

    if (fTop)
    {
        mousePosition += m_pGaulemCameraComponent->GetPosition();
    }
    else
    {
        mousePosition += m_pBaseCameraComponent->GetPosition();
    }

    //Find out where we clicked
    string entityGroup = "top";
    if (mousePosition.GetY() >= yOffset)
    {
        entityGroup = "bottom";
    }

    for each (Entity* pEntity in entityManager.GetEntityDataStore(entityGroup))
    {
        if (pEntity)
        {
            auto bbComponent = pEntity->GetComponent<BoundingBoxComponent>();
            auto transformComponent = pEntity->GetComponent<TransformComponent>();
            auto gaulemRenderableComponent = pEntity->GetComponent<GaulemRenderableComponent>();

            if (bbComponent && transformComponent && gaulemRenderableComponent)
            {
                SDL_Rect rect;
                rect.w = static_cast<int>(bbComponent->GetDimension().GetX());
                rect.h = static_cast<int>(bbComponent->GetDimension().GetY());
                rect.x = static_cast<int>(transformComponent->GetPosition().GetX());
                rect.y = static_cast<int>(transformComponent->GetPosition().GetY() + (gaulemRenderableComponent->IsOnTop() ? 0 : yOffset));

                if (Utilities::PointInRectangleTest(mousePosition, rect))
                {
                    m_clickedEntities.push_back(pEntity);
                }
            }
        }
    }
}

bool GameStateUserInterface::OnMouseMoved(const Vector2D<s32>& absolute, const Vector2D<s32>& relative)
{
    if (!CameraHelper::IsOnTop(absolute, m_resolution))
    {
        //Snap it to the tiles
        auto bottomPosition = CameraHelper::AbsoluteToLogicalPosition(absolute, m_resolution);
        auto rowCol = (bottomPosition / 64) * 64;
        auto realPosition = CameraHelper::LogicalToAbsolutePosition(rowCol, m_resolution, false);
        m_activePictureOnMouse->SetPosition(realPosition);      
    }

    return false;
}

bool GameStateUserInterface::OnMouseButtonPressed(const Vector2D<s32>& absolute, s32 button)
{
    if (IsLeftButton(button))
    {
        switch (m_state)
        {
        case UIState::eShowingNothingOnMouse:
            FindClickedEntities(*m_pGameEngine, absolute);
            m_clickTimer->start();
            break;
        case UIState::eShowingActivePictureOnMouse:
            auto& world = m_pGameStateObject->GetWorld();
            world.AddRoom(World::RoomType::e128, CameraHelper::AbsoluteToLogicalPosition(absolute, m_resolution));
            break;
        }

    }

    return false;
}

bool GameStateUserInterface::OnMouseButtonReleased(const Vector2D<s32>& absolute, s32 button)
{
    switch (m_state)
    {
    case UIState::eShowingNothingOnMouse:
        m_clickTimer->stop();
        m_elapsedClickTime = static_cast<u32>(m_clickTimer->getElapsedTimeInMilliSec());
        break;
    case UIState::eShowingActivePictureOnMouse:
        break;
    }

    return false;
}

bool GameStateUserInterface::HandleEvent(const Event& evt)
{
    switch (evt.GetEventType())
    {
    case Event::eEntityEvent:
            auto pEvent = evt.GetEvent<EntityEvent>();

            if (pEvent)
            {
                if (m_pBaseCameraComponent == nullptr || m_pGaulemCameraComponent == nullptr)
                {
                    if (pEvent->IsEntityAdded())
                    {
                        Entity& entity = pEvent->GetEntity();

                        if (entity.GetName() == "GaulemCamera")
                        {
                            m_pGaulemCameraComponent = entity.GetComponent<CameraComponent>();
                        }
                        else if (entity.GetName() == "BaseCamera")
                        {
                            m_pBaseCameraComponent = entity.GetComponent<CameraComponent>();
                        }
                    }
                }
            }
        break;
    }
    return false;
}

void GameStateUserInterface::SetActivePictureOnMouse(const string& group, const string& image)
{
    m_state = eShowingActivePictureOnMouse;
    m_activePictureOnMouse->SetPicture(group, image);
    m_activePictureOnMouse->Show();
}